﻿using Marvin.Optimization;
using MathNet.Numerics.LinearAlgebra.Double;
using MathNet.Numerics.LinearAlgebra.Generic;

namespace Marvin.Prediction.LinearRegression
{
    class GradientFunction: IGradientFunction
    {
        private readonly Matrix<double> _xMatrix;

        private readonly Vector<double> _y;

        private readonly int _dimensions;
        private readonly int _trainingExamples; 

        public GradientFunction(Matrix<double> x, Vector<double> y )
        {
            _dimensions = x.ColumnCount + 1;
            _trainingExamples = x.RowCount;

            _xMatrix = new DenseMatrix(x.RowCount, x.ColumnCount + 1, 1.0);
            _xMatrix.SetSubMatrix(0, x.RowCount, 1, x.ColumnCount, x);

            _y = y; 
        }


        public Vector<double> Calculate(Vector<double> theta)
        {
            Vector<double> error = (_xMatrix * theta) - _y;

            
            var gradient = (_xMatrix.Transpose() * error) / _trainingExamples; 

            return gradient; 
        }

        public int GetDimension()
        {
            return _dimensions;
        }
    }
}
